<?

  require_once 'Tree.class.php';

  class HOGTree extends Tree
  {
    public $id  = null;
    public $spc = null;
    public $len = null;
    public $bs  = null;
    public $alc = null;
    public $blc = null;
    public $d   = null;
    public static $bacIDs;
    public static $maxID=0;

    public function __construct( Tree $source, HOGTree $parent=null )
    {
      parent::__construct( $source->label, $parent );
      $this->id   = ++HOGTree::$maxID;
      $this->info = $source->info;
      foreach ( $source->children as $child )
        new HOGTree( $child, $this );
      $this->parseLabel();
      $this->defineStats();
    }

    private function parseLabel()
    {
      $label = $this->label;

      // branch length
      if ( preg_match( "~:(\d+(\.\d+)?(e-\d+)?)$~", $label, $parts ) )
      {
        $this->len = floatval($parts[1]);
        $label = preg_replace( "~:$parts[1]$~", "", $label );
      }

      if ( $this->isLeaf() )
        if ( empty($label) )
          $this->spc = $label;
        elseif ( preg_match( "~^([A-Za-z]+[0-9]*)(_|$)~", $label, $parts ) )
          $this->spc = $parts[1];
        else
          echo "Strange leaf label: '$label',\n";
      else
        if ( empty($label) )
          $this->bs = -1;
        elseif ( preg_match( "~^[0-9]+$~", $label ) )
          $this->bs = intval($label);
        else
          echo "Strange non-leaf label: '$label'.\n";

      $this->label = $label;
    }

    function defineStats()
    {
      $this->alc = $this->numberOfLeaves();
      $this->blc = $this->numberOfBacLeaves();
    }

    public function root()
    {
      if ( $this->isRoot() )
        return $this;
      else
        return $this->parent->root();
    }

/*    public function getSpeciesList()
    {
      if ( $this->isLeaf() )
        return array( $this->spc );

      $spList = array();
      foreach ( $this->children as $child )
        $spList = array_merge( $spList, $child->getSpeciesList() );
      return $spList;
    }*/

    public function numberOfLeaves()
    {
      if ( $this->alc !== null )
        return $this->alc;
      $nb = 0;
      if ( $this->isLeaf() )
        return 1;
      else
        foreach ( $this->children as $child )
          $nb += $child->numberOfLeaves();
      return $nb;
    }

    public function numberOfBacLeaves()
    {
      if ( $this->blc !== null )
        return $this->blc;
      $nb = 0;
      if ( $this->isLeaf() )
        return ( $this->isBacterium() ? 1 : 0 );
      else
        foreach ( $this->children as $child )
          $nb += $child->numberOfBacLeaves();
      return $nb;
    }

    public function isBacterium()
    {
      if ( !$this->isLeaf() )
        return false;
      else
        return in_array( $this->spc, self::$bacIDs );
    }

    public function hasNonBacLeaf()
    {
      return $this->alc - $this->blc > 0;
    }

    public function calcD_rec()
    {
      $this->calcD();
      if ( !$this->isLeaf() )
        foreach ( $this->children as &$child )
          $child->calcD_rec();
    }

    public function calcD()
    {
      if ( $this->isRoot() )
        return;
      $l1 = $this->alc;
      $l0 = $this->root()->alc - $l1;
      $b1 = $this->blc;
      $b0 = $this->root()->blc - $b1;
      $d1 = $b1/$l1;
      $d0 = $b0/$l0;
      $d = pow( sqrt($d1) - sqrt($d0), 2 );
      $this->d = $d;
    }

    public function getDList()
    {
      $dList = array();

      if ( !$this->isRoot() )
        $dList[$this->id] = $this->d;

      foreach ( $this->children as $child )
        $dList = array_merge( $dList, $child->getDList() );
      return $dList;
    }

    public function toNewickCompact( $root=true )
    {
      $label = $this->label;
//      $this->label = $this->isLeaf() ? $this->spc : $this->bs;

$this->label = "";
if ( $this->isLeaf() )
  $this->label .= ( $this->isBacterium() ? 'B_' : 'A_' );
$this->label .= $this->spc . "_D" . number_format( 100*$this->d );
      $result = parent::toNewickCompact(false);
      $this->label = $label;

      if ( $root )
        $result .= ';';

      return $result;
    }

  }

HOGTree::$bacIDs = null;

?>
